
/****************************************************************************
**
** Copyright (C) 2004-2008 VATATA.com . All rights reserved.
**
** This file is the part of the Miniutil Poject of VATATA.com.
** Vatata's miniutil library is lightweight and portable (for linux
** and Windows). The C++ Class Library included Threadpool, Dll danymic loading, 
** General socket application model and tcp server, httpserver/servlet, etc. 
** It is a pratical utility disigned for who don't want learn the Big C++ 
** Developing Platform, such as  Boost or ACE.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by VATATA.com.
** (or its successors, if any) and the Miniutil Project Aministrators. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://www.gnu.org/licenses/lgpl.html. If you are unsure which 
** license is appropriate for your use, please review the following 
** information: http://code.google.com/p/miniutil/ or contact 
** http://www.vatata.com.
**
** In addition, as a special exception, VATATA.com, as the sole
** copyright holder for Miniutil Project, grants users of VATATA
** P2P Platform the right to release and package with the related 
** libraries without the source code.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. vatata reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/





#ifdef WIN32
# include <winsock2.h>

#include <windows.h>

#else
#include <sys/time.h>
#endif

#include <stdio.h>
#include <string.h>
#include <time.h>
#include "miniutil/strutil.h"
#include "miniutil/date.h"

namespace miniutil
{

static miniutil::m_uint32_t startSecond = date::currentSec();

miniutil::m_uint32_t date::currentSec()
{
	return (unsigned long) time(NULL);
}


miniutil::m_uint32_t date::relativeMSec()
{
	m_uint32_t msec;
#ifdef WIN32
	msec = GetTickCount();
#else
	struct timeval tv;
	struct timezone tz;

	gettimeofday(&tv, &tz);

	msec = (tv.tv_sec - startSecond ) * 1000L + tv.tv_usec / 1000L;

#endif
	return msec;
}

static miniutil::m_uint32_t starttime_ms = date::relativeMSec();

miniutil::m_uint32_t date::uptime_ms()
{
	miniutil::m_uint32_t msec = relativeMSec() - starttime_ms; 
	return msec;
}

miniutil::m_uint64_t date::currentMSec()
{
#ifdef WIN32
	FILETIME ft;

	GetSystemTimeAsFileTime( &ft );

  // Microsoft's millis start in the year 1601.
  // 11644473600000L = ((1970 - 1601) * 365 + 89) * 24 * 60 * 60 * 1000

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
	return ((unsigned long long)ft.dwLowDateTime | ((unsigned long long)ft.dwHighDateTime << 32)) 
		/ 10000UI64 - 11644473600000UI64;
#else
	return ((unsigned long long)ft.dwLowDateTime | ((unsigned long long)ft.dwHighDateTime << 32)) 
		/ 10000LL - 11644473600000LL;
#endif

#else
	struct timeval tv;
	struct timezone tz;

	gettimeofday(&tv, &tz);

	return (tv.tv_sec - startSecond ) * 1000LL + tv.tv_usec / 1000LL;
#endif
}

static const char * weeks[]  = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char * months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct","Nov","Dec"};

string date::getDateString( const char * format )
{
	char buf[1024];
	time_t sec = (time_t) (this->msec / 1000 );
	//struct tm * tsec = gmtime( &sec );
	struct tm * tsec;
    
    if ( strchr( format, 'Z' ) )
        tsec = gmtime( &sec );
    else
        tsec = localtime( &sec );


	char *p = buf;
	char *f = (char *) format;
	while( p-buf < 1000 )
	{
        if (*f == 0x00) //end of format
            break;

		if ( *f != '%' )
		{
			*p++ = *f ++ ;
			continue;
		}
		++f ;
		switch( *f++ )
		{
		case 'a':
			p+= sprintf(p, "%s", weeks[ tsec->tm_wday ] );
			break;
		case 'b':
		case 'h':
			p+= sprintf(p, "%s", months[tsec->tm_mon] );
			break;
		case 'd':
			p+= sprintf(p, "%2d", tsec->tm_mday );
			break;
		case 'e':
			p+= sprintf(p, "%d", tsec->tm_mday );
			break;
		case 'g':
		case 'y':
			p+= sprintf(p, "%2d", tsec->tm_year % 100 );
			break;
		case 'G':
		case 'Y':
			p+= sprintf(p, "%4d", (tsec->tm_year) + 1900 );
			break;
		case 'H':
			p+= sprintf(p, "%2d", tsec->tm_hour );
			break;
		case 'j':
			p+= sprintf(p, "%3d", tsec->tm_yday );
			break;
		case 'm':
			p+= sprintf(p, "%2d", tsec->tm_mon );
			break;
		case 'q':
			if ( tsec->tm_mon + 1 < 10 )
				p+= sprintf(p, "0%1d", tsec->tm_mon + 1 );
			else
				p+= sprintf(p, "%2d", tsec->tm_mon + 1 );
			break;
		case 'M':
			if ( tsec->tm_min < 10 )
				p+= sprintf(p, "0%1d", tsec->tm_min );
			else
				p+= sprintf(p, "%2d", tsec->tm_min );
			break;
		case 'S':
			if ( tsec->tm_sec < 10 )
				p+= sprintf(p, "0%1d", tsec->tm_sec );
			else
				p+= sprintf(p, "%2d", tsec->tm_sec );
			break;
		case 'u':
			p+= sprintf(p, "%d", tsec->tm_wday + 1 );
			break;
		case 'Z':
			p+= sprintf(p, "%s", "GMT");
			break;

		//TODO: more options...
		default:
			break;
		}
	}
	*p = '\0';
	return string(buf);
}


    int MonthIndex(std::string vle)
    {
	    const char *smons[] = { "Jan","Feb","Mar","Apr","May", "Jun","Jul","Aug",
		    "Sep","Oct","Nov","Dec" };
        const char *fmons[] = { "January", "February", "March", "April", "May", "June", "July", "August",
            "September", "October", "November", "December" };
	    int i;

	    for(i=0; i<12; i++) 
        {
            if( vle == smons[i] || vle == fmons[i] )
			    return i;
	    }
	    return -1;			/* Failed, impossible month! */
    }

    /*
        Convert the string ctime() generate back to time_t
        Www Mmm dd hh:mm:ss yyyy
    */

    int ReverseCTime(std::string vle, time_t& ti)
    {
        std::vector<std::string> vles = miniutil::strutil::split(vle, " ");
        if(vles.size() != 5)
            return -1;

        struct tm tm1;
        tm1.tm_mon = MonthIndex(vles[1]);
        if(tm1.tm_mon == -1)
            return -1;
        tm1.tm_mday = miniutil::strutil::parseInt(vles[2]);
        tm1.tm_year = miniutil::strutil::parseInt(vles[4]) - 1900;
        if(tm1.tm_year < 0)
            return -1;

        std::vector<std::string> vsecs = miniutil::strutil::split(vles[3], ":");
        if(vsecs.size() != 3)
            return -1;
        tm1.tm_hour = miniutil::strutil::parseInt(vsecs[0]);
        tm1.tm_min = miniutil::strutil::parseInt(vsecs[1]);
        tm1.tm_sec = miniutil::strutil::parseInt(vsecs[2]);
        tm1.tm_isdst = -1;

        ti = mktime(&tm1);
        return 0;
    }

} 

